package com.pentajock.docdb.dialogs;

/*
 * Liscense: 	GPL http://www.gnu.org/copyleft/gpl.html
 * By: 		A. Tres Finocchiaro
 * Date:	2007
 * Java:	6.0SE
 */


import com.pentajock.docdb.Main;
import com.pentajock.docdb.database.DBController;
import com.pentajock.docdb.images.DBImages;
import com.pentajock.docdb.lang.Lang;
import com.pentajock.docdb.listeners.AutoTextSelectionFocusListener;
import com.pentajock.docdb.types.User;
import com.pentajock.docdb.utils.Utils;
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import java.util.*;
import javax.swing.*; 

public class PasswordDialog extends JDialog {
	private static final String CANCEL_DIALOG_INPUT_KEY = "CANCEL_DIALOG";
	
	private JPasswordField originalPassField;
	private JPasswordField newPassField;
	private JPasswordField confirmPassField;
	private JButton okButton;
	private JButton cancelButton;
	
	private String user;
	private boolean firstLoginMode;
	private boolean adminOverride;
	private boolean success;
	private String OK = Lang.BUTTON.getText("OK", "Ok");
	private String CANCEL = Lang.BUTTON.getText("CANCEL", "Cancel");
	
	private int OK_KEY = Lang.BUTTON.getMnemonic("OK", KeyEvent.VK_O);
	private int CANCEL_KEY = Lang.BUTTON.getMnemonic("CANCEL", KeyEvent.VK_C);
	
	private String COLON = Lang.MISC.getText("CHOICE_DELIMITER", ":");
	private String NOT_AVAILABLE = Lang.MISC.getText("NOT_AVAILABLE", "<n/a>");
	
	private String TITLE = Lang.MENU.getText("PASSWORD", "Change Password");
	private String SET_FOR = Lang.DIALOG.getText("PASSWORD_SET_FOR", "Set Password for");
	
	
	private String CURRENT = Lang.DIALOG.getText("PASSWORD_CURRENT", "Current Password");
	private String NEW = Lang.DIALOG.getText("PASSWORD_NEW", "New Password");
	private String CONFIRM = Lang.DIALOG.getText("PASSWORD_CONFIRM", "Confirm Password");
	
	private int CURRENT_KEY = Lang.DIALOG.getMnemonic("PASSWORD_CURRENT", KeyEvent.VK_U);
	private int NEW_KEY = Lang.DIALOG.getMnemonic("PASSWORD_NEW", KeyEvent.VK_N);
	private int CONFIRM_KEY = Lang.DIALOG.getMnemonic("PASSWORD_CONFIRM", KeyEvent.VK_F);
	
	private String PASSWORD_ERROR = Lang.DIALOG.getText("PASSWORD_ERROR", "Error occured during password change.");
	private String PASSWORD_ERROR_MATCH = Lang.DIALOG.getText("PASSWORD_ERROR_MATCH", "New passwords do not match.");
	private String PASSWORD_ERROR_LENGTH=Lang.DIALOG.getText("PASSWORD_ERROR_LENGTH", "New password must be at least 4 characters long.");
	private String PASSWORD_ERROR_INCORRECT=Lang.DIALOG.getText("PASSWORD_ERROR_INCORRECT", "Current password is incorrect.");
	private String PASSWORD_SUCCESS_CHANGE=Lang.DIALOG.getText("PASSWORD_SUCCESS_CHANGE", "Password successfully changed.");
	private String PASSWORD_SUCCESS_CREATED=Lang.DIALOG.getText("PASSWORD_SUCCESS_CREATED", "Your password has been created.");
	
	
	public PasswordDialog(Frame owner) {
		super(owner, true);
		setTitle(TITLE);
		constructHelper(false, false, null);
	}
	
	public PasswordDialog(Frame owner, String userName) {
		super(owner, true);
		constructHelper(false, false, userName);
	}

	public PasswordDialog(Dialog owner, boolean firstLoginMode) {
		super(owner, true);
		constructHelper(firstLoginMode, false, null);
	}
	
	public PasswordDialog(Dialog owner, boolean firstLoginMode, String userName) {
		super(owner,true);
		constructHelper(firstLoginMode, false, userName);
	}
	
	/*
	 * Constructor specifically for the Admin's DBUserDialog
	 */
	public PasswordDialog(Dialog owner, User editUser, User adminUser) {
		super(owner, true);
		if (DBController.getUserIsAdmin(adminUser)) {
			constructHelper(false, true, editUser.getUserName());
		}
	}
	
	private void constructHelper(boolean firstLoginMode, boolean adminOverride, String userName) {
		setTitle(adminOverride? SET_FOR + COLON + " " + userName : TITLE);
		setUser(userName);
		this.firstLoginMode = firstLoginMode;
		this.adminOverride = adminOverride;
		success = false;
		Utils.setIconImage(this, DBImages.LOGIN_WINDOW.getImage());
		initializeObjects();
		layoutFrame();
		addListeners();
		getRootPane().setDefaultButton(okButton);
		setResizable(false);
		pack();
		setLocationRelativeTo(null);
	}
	
	private void initializeObjects() {
		originalPassField = new JPasswordField(10);
		if(firstLoginMode || adminOverride) {
			originalPassField.setText(NOT_AVAILABLE);
			originalPassField.setEnabled(false);
		}
		newPassField = new JPasswordField(10);
		confirmPassField = new JPasswordField(10);
		
		okButton = new JButton(OK);
		okButton.setDefaultCapable(true);
		okButton.setMnemonic(OK_KEY);
		
		cancelButton = new JButton(CANCEL);
		cancelButton.setMnemonic(CANCEL_KEY);
	}
	
	private void layoutFrame() {
		JLabel originalPassLabel = new JLabel(CURRENT + COLON);
		originalPassLabel.setDisplayedMnemonic(CURRENT_KEY);
		originalPassLabel.setLabelFor(originalPassField);
		originalPassLabel.setHorizontalAlignment(SwingConstants.RIGHT);
		
		JLabel newPassLabel = new JLabel(NEW + COLON);
		newPassLabel.setDisplayedMnemonic(NEW_KEY);
		newPassLabel.setLabelFor(newPassField);
		newPassLabel.setHorizontalAlignment(SwingConstants.RIGHT);
		
		JLabel confirmPassLabel = new JLabel(CONFIRM + COLON);
		confirmPassLabel.setDisplayedMnemonic(CONFIRM_KEY);
		confirmPassLabel.setLabelFor(confirmPassField);
		confirmPassLabel.setHorizontalAlignment(SwingConstants.RIGHT);
		
		JPanel originalPassPanel = new JPanel(new GridLayout(1, 2, 4, 4));
		originalPassPanel.add(originalPassLabel);
		originalPassPanel.add(originalPassField);
		originalPassPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
		
		JPanel newPassPanel = new JPanel(new GridLayout(2, 2, 4, 4));
		newPassPanel.add(newPassLabel);
		newPassPanel.add(newPassField);
		newPassPanel.add(confirmPassLabel);
		newPassPanel.add(confirmPassField);
		newPassPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
		
		JPanel buttonPanel = new JPanel(new FlowLayout());
		buttonPanel.add(okButton);
		buttonPanel.add(cancelButton);
		buttonPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
		
		Container contentPane = getContentPane();
		contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
		contentPane.add(originalPassPanel);
		contentPane.add(Box.createVerticalStrut(3));
		contentPane.add(new JSeparator(SwingConstants.HORIZONTAL));
		contentPane.add(Box.createVerticalStrut(3));
		contentPane.add(newPassPanel);
		contentPane.add(buttonPanel);
	}
	
	private void addListeners() {
		addComponentListener(new ComponentAdapter() {
			public void componentShown(ComponentEvent e) {
				if(firstLoginMode) {
					newPassField.requestFocusInWindow();
				}
				else {
					originalPassField.requestFocusInWindow();
				}
			}
		});
		
		okButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				String originalPass = new String(originalPassField.getPassword());
				boolean originalPassMatches = false;
				
				if(firstLoginMode || adminOverride) {
					originalPassMatches = true;
				}
				else {
					try {
						originalPassMatches = DBController.checkPassword(user, originalPass);
					}
					catch(SQLException ex) {
						Main.printStackTrace(ex, "Problem with password check.");
					}
				}
				
				if(originalPassMatches) {
					if(newPasswordsMatch()) {
						String newPass = new String(confirmPassField.getPassword());
						if(newPass.length() < 4) {
							showError(PASSWORD_ERROR_LENGTH);
							resetFields();
						}
						else if(adminOverride && DBController.changeUserPassword(user, newPass, "Passphrase")) {
							success = true;
							setVisible(false);
						}
						else if(!firstLoginMode && DBController.changePassword(user, originalPass, newPass)) {
							showSuccess(PASSWORD_SUCCESS_CHANGE);
							success = true;
							setVisible(false);
						}
						else if(firstLoginMode && DBController.setFirstPassword(user, newPass)) {
							showSuccess(PASSWORD_SUCCESS_CREATED);
							success = true;
							setVisible(false);
						}
						else {
							showError(PASSWORD_ERROR);
							resetFields();
						}
					}
					else {
						showError(PASSWORD_ERROR_MATCH);
						resetFields();
					}
				}
				else {
					showError(PASSWORD_ERROR_INCORRECT);
					resetFields();
				}
			}
		});
		
		cancelButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				setVisible(false);
			}
		});
		
		originalPassField.addFocusListener(new AutoTextSelectionFocusListener(originalPassField));
		newPassField.addFocusListener(new AutoTextSelectionFocusListener(newPassField));
		confirmPassField.addFocusListener(new AutoTextSelectionFocusListener(confirmPassField));
		
		/*
		 * Input/Action mapping.
		 */
		InputMap inputMap = new ComponentInputMap((JComponent)getContentPane());
		inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), CANCEL_DIALOG_INPUT_KEY);
		
		ActionMap actionMap = new ActionMap();
		actionMap.put(CANCEL_DIALOG_INPUT_KEY, new AbstractAction() {
			public void actionPerformed(ActionEvent e) {
				setVisible(false);
			}
		});
		
		((JComponent)getContentPane()).setInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW, inputMap);
		((JComponent)getContentPane()).setActionMap(actionMap);
		/**/
	}
	
	private void showSuccess(String message) {
		Dialogs.showSuccess(message);
	}
	
	private void showError(String message) {
		Dialogs.showError(message);
	}
	
	private boolean newPasswordsMatch() {
		return Arrays.equals(newPassField.getPassword(), confirmPassField.getPassword());
	}
	
	private void resetFields() {
		originalPassField.setText("");
		newPassField.setText("");
		confirmPassField.setText("");
		originalPassField.requestFocusInWindow();
	}
	
	public void setUser(String user) {
		this.user = user;
	}
	
	public boolean isSuccessful() {
		return success;
	}
	
	public void setVisible(boolean b) {
		if(b) {
			if(user == null && !firstLoginMode) {
				Main.printDebug("Username not set in change password dialog!");
				return;
			}
			resetFields();
			setLocationRelativeTo(null);
		}
		else {
			setUser(null);;
		}
		super.setVisible(b);
	}
}
